package services

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"github.com/xuri/excelize/v2"
	"io"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
	"wecom_rebot/common"
	"wecom_rebot/core"
	"wecom_rebot/models"
	"wecom_rebot/utils"
)

var copyAccountTxLogger *logrus.Logger

// InitCopyAccountLogger 移除 init() 函数，改为显式初始化函数
func InitCopyAccountLogger() {
	// 确保在 common 初始化后调用
	copyAccountTxLogger = core.InitLogger(common.LogsErrorMap[5])
}

type CopyAccountService struct{}

var SaleK1K6Person = map[string]string{
	"K1": "17338572", // 杨诗雨
	"K2": "18423018", // 程思婷
	"K3": "18423018", // 程思婷
	"K6": "17338572", // 杨诗雨
}
var SaleK4Person = map[string]string{
	"北京市":  "17136671", // 贾国帅
	"浙江省":  "11008627", // 关思洋
	"黑龙江省": "17485704", // 姜卓
	"吉林省":  "17485704", // 姜卓
	"辽宁省":  "17478863", // 钟宇婷
	"上海市":  "9890198",  // 郭凯敏
	"江苏省":  "11008627", // 关思洋
	"四川省":  "21652533", // 宗纪宇
	"海南省":  "19495297", // 周冠凯
	"福建省":  "17472927", // 吴让增
}

// AccountInfoRequest 定义广告主信息结构体
type AccountInfoRequest struct {
	AccountID   []string
	Number      string
	Username    string
	ReplyFile   string
	subjectName string
}

// getAgencyUidList 服务商UID列表（需要根据实际业务实现）
func (s *CopyAccountService) getAgencyUidList() []int {
	// 这里需要根据您的业务逻辑实现
	// 示例返回固定值
	return []int{
		6985731, 9968121, 11008627, 14651290, 14707475, 15110328, 17063561, 17132468, 19121686, 19449501, 19470704, 19471436, 19472587, 19473163, 19473174, 19473210, 19473226, 19508174, 19508184, 19508202, 19508222, 19508230, 19508234, 19508263, 19508304, 19530867, 19531158, 19531345, 19534314, 19534325, 19534345, 19534363, 19540155, 19544762, 19544775, 19544778, 19562677, 19879798, 20012613, 20012619, 20012778, 20012783, 20012787, 21334203, 21480155, 21762737, 21762785, 22092868, 22092878, 22092888, 22092897, 22093252, 22381729, 22865592, 22865644, 22946031, 22946053, 23217691, 23220674, 23257334, 23317107, 24311660, 25054539, 26170732, 26170739, 26348959, 26735143, 29660895, 30216617, 30216633, 30367019, 30732233, 30732300, 30732328, 30732365, 30732415, 30732465, 30732498, 30732535, 30899382, 31140557, 31408090, 31423368, 31487016, 31629801, 43180968, 43407195, 43435866, 43450032, 43484653, 43485205, 43485539, 43485878, 43486659, 43489059, 43489510, 43490993, 43495368, 43496360, 43514305, 43522073, 43528047, 43528618, 43557905, 43558693, 43562378, 43582281, 43685770, 43686516, 43697965, 43711134, 43713628, 43714462, 43715737, 43716857, 43718673, 43721196, 43726603, 43802254, 43805509, 43813213, 43818548, 43821769, 43825000, 43834893, 43847396, 43848840, 43850806, 43852123, 43852606, 43864921, 43883935, 43894812, 43895539, 43978959, 44120612, 44121687, 44121910, 44124978, 44137366, 44144206, 44252949, 44253562, 44255895, 44275745, 44340329, 44343097, 44344741, 44378071, 44378431, 44378965, 44383057, 44393959, 44530866, 44544476, 44572211, 44573086, 44578776, 44582080, 44582309, 44610995, 44619421, 44622434, 44647703, 44655080, 44672739, 44679688, 44751956, 44752217, 44793417, 44846714, 45056922, 45057284, 45063820, 45118556, 45129413, 45174546, 45215103, 45359075, 45465080, 45477599, 45486872, 45491792, 45502369, 45505450, 45514057, 45597251, 45597485, 45601079, 45663151, 45758689, 45758861, 45758882, 45759095, 45759455, 45760069, 45760725, 45760967, 45762935, 45766357, 45794070, 45811063, 45935695, 45935975, 45936064, 45936396, 45936872, 45939348, 45944123, 45944628, 45949936, 45951557, 45977279, 46001443, 46004917, 46024050, 46024117, 46024796, 46025061, 46025146, 46025527, 46025673, 46025771, 46026272, 46027841, 46030452, 46031854, 46034210, 46034570, 46035860, 46037846, 46040040, 46040948, 46041207, 46041505, 46041875, 46042836, 46045436, 46046013, 46077333, 46084976, 46085433, 46086946, 46087449, 46090449, 46090472, 46092126, 46168615, 46176140, 46176222, 46183818, 46193754, 46207064, 46209167, 46217756, 46225722, 46226127, 46232046, 46241669, 46242604, 46243358, 46247659, 46269018, 46273230, 46277356, 46277592, 46331614, 46339928, 46355511, 46371626, 46373139, 46373211, 46386328, 46452538, 46453065, 46500239, 46553038, 46574095, 46609489, 46640110, 46668219, 46668475, 46767043, 46768017, 46772457, 46854928, 46889327, 46929955, 46962262, 46963024, 46974782, 47044661, 47148952, 47154052, 47156852, 47172516, 47362296, 47370739, 47427234, 47501682, 47505754, 47515442, 47557398, 47557589, 47567169, 47814315, 47817160, 47877417, 47880601, 47959111, 47966963, 47971004, 48008476, 48083020, 48136743, 48197194, 48200420, 48465094, 48631531, 48632117, 48632296, 48701822, 48718673, 48835958, 48865049, 49538002, 49616106, 49778949, 49799329, 49964621, 50129044, 50129349, 50160920, 50173475, 50284233, 50285315, 50286737, 50303442, 50329378, 50336703, 50340965, 50349546, 50420110, 50531406, 50532454, 50561951, 50634368, 50795644, 50832075, 50904637, 50912525, 50960309, 51102028, 51104278, 51130246, 51179164, 51180424, 51229554, 51276748, 51300953, 51509064, 51523711, 51533579, 51564403, 51582269, 51587983, 51597045, 51627300, 51628140, 51665276, 51713005, 51827920, 51828751, 51853522, 51899870, 51918075, 51921092, 51928952, 51948756, 51995463, 51995573, 52032393, 52039745, 52048196, 52076701, 52108254, 52127861, 52212325, 52217050, 52236265, 52247578, 52260795, 52304338, 52319537, 52320243, 52380261, 52397018, 52473178, 52474391, 52512231, 52528287, 52656717, 52864253, 52867146, 52873364, 52919158, 52956841, 53072112, 53170244, 53176795, 53212735, 53264553, 53271442, 53364449, 53366336, 53371300, 53468165, 53522238, 53588140, 53602544, 53718106, 53737363, 53826872, 53854653, 53959936, 53960684, 54052285, 54087451, 54095445, 54230125, 54238677, 54314475, 54348158, 54390830, 54427688, 54656273, 54866345, 54951761, 54968900, 55146094, 55342555, 55467804, 55699667, 55700183, 55704274, 55720685, 55722193, 55726820, 55772367, 55803470, 55805620, 55859358, 55971590, 56013476, 56022654, 56098805, 56129652, 56337099, 56341110, 56367827, 56452807, 56455158, 56455368, 56472655, 56491952, 56541673, 56618241, 56619563, 56707629, 56708321, 56714371, 56788420, 56788953, 56792995, 56795620, 56849974, 56941939, 56979205, 57096874, 57171223, 57178601, 57180964, 57186218, 57234364, 57290297, 57332980, 57375047, 57483698, 57584893, 57587538, 57657996, 57698937, 57718626, 57731708, 57881846, 57883460, 57919372, 57951033, 57955873, 57957465, 57983235, 58011743, 58202223, 58251318, 58253138, 58313072, 58318573, 58410153, 58476570, 58512475, 58526920, 58768640, 58802575, 58807765, 58927832, 58979708, 58983786, 59014298, 59040559, 59051930, 59095682, 59126563, 59178931, 59183303, 59362315, 59473382, 59853124, 59868259, 59877857, 59908748, 59914877, 59971402, 59992511, 59997683, 60070859, 60196193, 60240764, 60472943, 60532900, 60564183, 60573062, 60709355, 60715771, 60881590, 60947884, 61093578, 61208550, 61249224, 61697858, 61800168, 62168132, 62277975, 62313206, 62463239, 62504136, 62534801, 62544633, 62624237, 62640123, 62910212, 62910251, 62987922, 63058911, 63060074, 63082535, 63197858, 63250537, 63262059, 63266886, 63357469, 63452307, 63533926, 63534483, 63536979, 63548063, 63911755, 63940874, 64108822, 64139997, 64273001, 64474629, 64599497, 64679374, 64875847, 64890250, 65048956, 65052109, 65101752, 65166999, 65199618, 65451326, 65465465}
}

func (s *CopyAccountService) Handle(msgId int, subjectName, roomId string, content []string, jobId uint64) error {
	var msg = &models.Msg{}

	fmt.Println("CopyAccountService", "原始结构Id：", msgId)
	// 获取数据
	err := common.DB.Where("id = ?", msgId).First(&msg).Error
	if err != nil {
		copyAccountTxLogger.Error("腾讯获取数据失败", common.LogsErrorMap[common.MysqlError], msgId, err)
		return err
	}

	copyAccountTxLogger.Info("CopyAccountService", "原始结构：", content)

	// 处理需要的数据结构
	accounts, err := s.analyzeContent(content)
	if err != nil {
		copyAccountTxLogger.Error(err)
		return err
	}

	err = s.checkCopyNumber(accounts.AccountID)
	if err != nil {
		copyAccountTxLogger.Error(err)
		return err
	}

	// 移除功能行
	msg.Content = RemoveTitle(msg)
	fmt.Println("CopyAccountService", accounts, "移除后的结构：", msg, "广告主信息：", content)

	rdb := core.InitRedis(13)
	ctx := context.Background()

	cookies, err := rdb.Get(ctx, "laravel_database_tencent_adv_cookies").Result()
	tk, err := rdb.Get(ctx, "laravel_database_tencent_adv_g_tk").Result()

	fmt.Println("CopyAccountService", "Cookies:", cookies, "tk:", tk)

	// 查询任务
	var job models.Job
	if err = common.DB.Where("id = ?", jobId).First(&job).Error; err != nil {
		copyAccountTxLogger.Error("查询完整任务记录", common.LogsErrorMap[2], jobId, err)
		return err
	}

	// 初始化结果集合
	var successAccounts []string
	var insertAllData []models.CopyAccountList

	for _, account := range accounts.AccountID {
		copyAccountTxLogger.Info("获取整个account结果", accounts.AccountID)
		fmt.Println("account", account)

		// 针对销售主动发起的腾讯复制户处理
		if msg.RoomID == "wrWGQCCQAAZimRyL3bF64zE-LniOkTiA" {
			if len(successAccounts) > 1 {
				msg.Content += "\n-----------------------------------\n复制账户数量不能大于1个，请重新输入"
				if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
					copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
				}
				break
			}

			var saleSendCopy models.SaleQwCopyContent
			err = common.DBDk.Where("qw_id = ?", roomId).First(&saleSendCopy).Error
			if err != nil {
				copyAccountTxLogger.Error("查询销售信息失败", common.LogsErrorMap[2], roomId, err)
			}

			copyAccountTxLogger.Info("销售发起的复制户信息：", saleSendCopy)

			// status == 1 同意 2 拒绝 3 待定 默认
			if saleSendCopy.Status == 3 {
				var accountInfo models.TencentAccountView
				err = common.DBDk.Raw("SELECT * FROM view_tencent_account WHERE account_id = ? AND is_old = 1", successAccounts[0]).First(&accountInfo).Error
				if err != nil {
					copyAccountTxLogger.Error("未找到销售复制的账户：", successAccounts[0])
					break
				}

				var limitation models.SaleQwCopyLimitation
				err = common.DBDk.Where("primary_industry = ? AND second_industry = ?", accountInfo.PrimaryIndustry, accountInfo.SecondIndustry).Take(&limitation).Error
				if err != nil {
					copyAccountTxLogger.Error("复制账户的一二级行业未经许可不允许复制：", account, accountInfo)
					msg.Content += "\n-----------------------------------\n账号（" + successAccounts[0] + "）：一二级行业（" + accountInfo.PrimaryIndustry + "），（" + accountInfo.SecondIndustry + "）"
					if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
						copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
					}
					break
				}

			}

		}

		if job.Status == 30 {
			return errors.New("任务已取消")
		}

		var accountInfo models.TencentAccountView
		if err = common.DBDk.Raw("SELECT * FROM view_tencent_account WHERE account_id = ? AND is_old = 1", account).Scan(&accountInfo).Error; err != nil {
			msg.Content += "\n-----------------------------------\n未找到广告主ID信息（" + account + "），请检查广告主表"
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}

		copyAccountTxLogger.Infof("项目匹配: %v, 输入项目: %s", accountInfo, accounts.subjectName)
		if accountInfo.Company != accounts.subjectName {
			msg.Content += "\n-----------------------------------\n项目名称不匹配（" + account + "），请检查广告主表"
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}

		// 获取绑定人员
		copyUrl1 := "https://e.qq.com/agp/account_open_user/get?g_tk=" + tk
		copyData1 := map[string]interface{}{
			"bm_id":           15134508,
			"agency_uid":      6985731,
			"account_id_list": []string{account},
		}
		copyAccountTxLogger.Infof("请求绑定人员接口: %s, 参数: %v", copyUrl1, copyData1)

		var personData map[string]interface{}
		if err := utils.SendRequest(copyUrl1, "POST", copyData1, cookies, copyAccountTxLogger, &personData); err != nil {
			msg.Content += "\n-----------------------------------\n" + err.Error()
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}

		copyAccountTxLogger.Infof("获取绑定人员结果: %v", personData)

		if code, ok := personData["code"].(float64); !ok || code != 0 {
			if msgStr, ok := personData["msg"].(string); ok {
				msg.Content += "\n-----------------------------------\n" + msgStr
			} else {
				msg.Content += "\n-----------------------------------\n获取绑定人员失败"
			}
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}
		if code, ok := personData["code"].(float64); !ok || code != 0 {
			if msgStr, ok := personData["msg"].(string); ok {
				msg.Content += "\n-----------------------------------\n" + msgStr
			} else {
				msg.Content += "\n-----------------------------------\n获取绑定人员失败"
			}
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}

		var sale string
		if data, ok := personData["data"].([]map[string]interface{}); ok && len(data) > 0 {
			for _, user := range data {
				if openUserID, ok := user["open_user_id"].(float64); ok {
					// 将 float64 转换为 string
					sale = fmt.Sprintf("%.0f", openUserID) // 保留整数部分
					break
				}
			}
		}

		// 如果没有绑定人员，使用媒介信息
		if sale == "" {
			if belongKk := accountInfo.BelongKk; belongKk != "" {
				switch belongKk {
				case "K1", "K2", "K3", "K6":
					sale = SaleK1K6Person[belongKk]
				case "K4":
					if region, ok := SaleK4Person[accountInfo.Province]; ok {
						sale = region
					}
				}
			}
		}
		copyAccountTxLogger.Infof("获取的销售人员: %s", sale)

		// 发起复制请求
		copyUrl := "https://e.qq.com/agp/advertiser/copy?g_tk=" + tk
		copyData := map[string]interface{}{
			"bm_id":        15134508,
			"agency_uid":   6985731,
			"source_uid":   account,
			"copy_number":  accounts.Number,
			"open_user_id": sale,
		}
		copyAccountTxLogger.Infof("发起复制请求: %s, 参数: %v", copyUrl, copyData)

		var result map[string]interface{}
		if err := utils.SendRequest(copyUrl, "POST", copyData, cookies, copyAccountTxLogger, &result); err != nil {
			msg.Content += "\n-----------------------------------\n" + err.Error()
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}
		copyAccountTxLogger.Infof("腾讯响应结果: %v", result)

		if code, ok := result["code"].(float64); !ok || code != 0 {
			if msgStr, ok := result["msg"].(string); ok {
				msg.Content += "\n-----------------------------------\n" + msgStr
			} else {
				msg.Content += "\n-----------------------------------\n复制请求失败"
			}
			if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			continue
		}

		// 处理复制结果
		if data, ok := result["data"].(map[string]interface{}); ok {
			if errorMsg, ok := data["error_msg"].(string); ok && errorMsg != "" {
				// 非空 error_msg 才发送
				msg.Content += "\n-----------------------------------\n" + errorMsg + "请联系商务媒介处理（" + account + "）"
				if err := BendiSendText(msg.Content, msg.RoomID, msg.Sender); err != nil {
					copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
				}
			} else {
				// 处理复制成功的账户
				if copyList, ok := data["copy_uid_list"].([]interface{}); ok {
					for _, item := range copyList {
						if uid, ok := item.(float64); ok {
							uid := fmt.Sprintf("%.0f", uid)
							accountId, _ := strconv.Atoi(account)
							successAccounts = append(successAccounts, uid)
							uidInt, _ := strconv.Atoi(uid)
							insertAllData = append(insertAllData, models.CopyAccountList{
								Parent:       accountId,
								AccountID:    uidInt,
								HandleStatus: 1,
								CreatedAt:    time.Now(),
								Username:     accounts.Username,
							})
						}
					}
				}
			}
		}
	}

	// 去重处理
	successAccounts = s.removeDuplicates(successAccounts)
	insertAllData = s.removeDuplicateAccounts(insertAllData)

	// 数据入库
	if len(insertAllData) == 0 {
		if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"没有复制户", msg.RoomID, msg.Sender); err != nil {
			copyAccountTxLogger.Errorf("发送无复制户消息失败: %v", err)
		}
		return nil
	}

	copyAccountTxLogger.Infof("去重后数据: %v", insertAllData)
	if err := common.DB.Create(&insertAllData).Error; err != nil {
		copyAccountTxLogger.Errorf("数据入库异常: %v, 数据: %v", err, insertAllData)
		return errors.New("数据入库异常，请检查日志: " + err.Error())
	}

	// 入库成功后，删除 jobs 表中对应记录
	//if err := common.DB.Delete(&job).Error; err != nil {
	//	copyAccountTxLogger.Errorf("已复制同步到OA，移除任务记录失败: %v", err)
	//}

	if accounts.ReplyFile == "是" {
		// 发送文件逻辑
		// 获取腾讯广告主信息
		tencentAccountGetList, err := s.getAccountCompanyJcRecursion(cookies, tk, successAccounts)
		if err != nil {
			copyAccountTxLogger.Errorf("获取腾讯广告主信息失败: %v", err)
			if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"获取腾讯广告主信息失败", msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			return errors.New("获取腾讯广告主信息失败，请检查日志: " + err.Error())
		}
		copyAccountTxLogger.Infof("获取腾讯账号的结果: %+v", tencentAccountGetList)

		// 插入数据库
		if data, ok := tencentAccountGetList["data"].(map[string]interface{}); ok {
			if list, ok := data["list"].([]interface{}); ok {
				var createData []models.TencentData
				for _, item := range list {
					if v, ok := item.(map[string]interface{}); ok {
						createData = append(createData, models.TencentData{
							Uname:                    v["uname"].(string),
							Uid:                      strconv.Itoa(int(v["uid"].(float64))),
							CustomerStatusName:       v["customer_status_name"].(string),
							IndustryFirstName:        v["industry_first_name"].(string),
							IndustrySecondName:       v["industry_second_name"].(string),
							AgencyUid:                strconv.Itoa(int(v["agency_uid"].(float64))),
							AgencyRemark:             v["agency_remark"].(string),
							BuyingTypeName:           v["buying_type_name"].(string),
							IdentityVerifyStatusName: v["identity_verify_status_name"].(string),
						})
					}
				}
				if len(createData) > 0 {
					if err := common.DB.Table("tencent_data").Create(&createData).Error; err != nil {
						copyAccountTxLogger.Errorf("数据入库失败: %v", err)
						if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"数据入库失败", msg.RoomID, msg.Sender); err != nil {
							copyAccountTxLogger.Errorf("插入数据库时发送错误消息失败: %v", err)
						}
						return errors.New("数据入库异常，请检查日志: " + err.Error())
					}
				}
			}
		}

		// 查询数据
		var dataList []models.TencentData
		if err := common.DB.
			Where("uid IN (?)", successAccounts).
			Find(&dataList).Error; err != nil {
			copyAccountTxLogger.Errorf("查询tencent_data失败: %v", err)
			if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"查询tencent_data失败", msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("查询数据库时发送错误消息失败: %v", err)
			}
			return errors.New("查询数据库异常，请检查日志: " + err.Error())
		}

		// 创建临时目录
		tempDir := "download/excel/"
		if _, err := os.Stat(tempDir); os.IsNotExist(err) {
			if err := os.MkdirAll(tempDir, 0755); err != nil {
				copyAccountTxLogger.Errorf("创建临时目录失败: %v", err)
				if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"创建临时目录失败", msg.RoomID, msg.Sender); err != nil {
					copyAccountTxLogger.Errorf("创建文件时发送错误消息失败: %v", err)
				}
				return errors.New("创建临时目录异常，请检查日志: " + err.Error())
			}
		}

		// 获取第一个广告主名称
		var firstUname string
		if len(dataList) > 0 {
			firstUname = dataList[0].Uname
		} else {
			firstUname = "未找到对应的主体名称"
		}

		// 清理文件名（仅保留中文、字母、数字）
		cleanName := regexp.MustCompile(`[^\p{Han}a-zA-Z0-9]`).ReplaceAllString(firstUname, "")
		counterKey := fmt.Sprintf("file_counter:%s:%s", cleanName, time.Now().Format("20060102"))
		counter, err := rdb.Incr(ctx, counterKey).Result()
		if err != nil {
			copyAccountTxLogger.Errorf("获取文件序号失败: %v", err)
			counter = 1
		}
		defer rdb.Expire(ctx, counterKey, 24*time.Hour) // 设置过期时间

		// 构造文件名
		fileName := fmt.Sprintf("%s_%s_%02d.xlsx", cleanName, time.Now().Format("20060102"), counter)
		tempFilePath := filepath.Join(tempDir, fileName)

		// 导出 Excel
		if !exportToExcel(dataList, tempFilePath) {
			if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"导出excel发送消息失败", msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("导出excel发送错误消息失败: %v", err)
			}
			return errors.New("导出excel异常，请检查日志: " + err.Error())
		}

		// 检查文件大小
		file, err := os.Open(tempFilePath)
		if err != nil {
			copyAccountTxLogger.Errorf("打开临时文件失败: %v", err)
			if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"打开临时文件失败", msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("打开临时文件，发送错误消息失败: %v", err)
			}
			return errors.New("打开临时文件异常，请检查日志: " + err.Error())
		}
		fi, err := file.Stat()
		if err != nil {
			copyAccountTxLogger.Errorf("获取文件信息失败: %v", err)
			if err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"获取文件信息失败", msg.RoomID, msg.Sender); err != nil {
				copyAccountTxLogger.Errorf("发送错误消息失败: %v", err)
			}
			file.Close()
			return errors.New("获取文件信息异常，请检查日志: " + err.Error())
		}
		if fi.Size() < 5 {
			err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"文件大小不符合要求（需大于5字节）", msg.RoomID, msg.Sender)
			if err != nil {
				copyAccountTxLogger.Errorf("文件大小不符合要求，发送错误消息失败: %v", err)
			}
			file.Close()
			os.Remove(tempFilePath)
			return errors.New("文件大小不符合要求，请检查日志: " + err.Error())
		}
		if fi.Size() > 20*1024*1024 { // 20M
			err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"文件大小超过限制（最大20M）", msg.RoomID, msg.Sender)
			if err != nil {
				copyAccountTxLogger.Errorf("文件大小超过限制，发送错误消息失败: %v", err)
				return nil
			}
			file.Close()
			os.Remove(tempFilePath)
			return errors.New("文件大小超过限制，请检查日志: " + err.Error())
		}
		file.Close()

		// 上传到企业微信
		mediaId, err := s.uploadMediaToWeCom(tempFilePath, fileName)
		copyAccountTxLogger.Infof("上传到企业微信的结果: %+v", mediaId)
		if err != nil {
			copyAccountTxLogger.Errorf("上传企业微信失败: %v", err)
			err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"上传企业微信失败", msg.RoomID, msg.Sender)
			if err != nil {
				copyAccountTxLogger.Errorf("上传企业微信失败，发送错误消息失败: %v", err)
				return nil
			}
			os.Remove(tempFilePath)
			return errors.New("上传企业微信异常，请检查日志: " + err.Error())
		}

		// 发送文件消息
		if err := BendiSendFile(msg.RoomID, mediaId); err != nil {
			copyAccountTxLogger.Errorf("发送文件失败: %v", err)
			err := BendiSendText(msg.Content+"\n-----------------------------------\n"+"发送文件失败", msg.RoomID, msg.Sender)
			if err != nil {
				copyAccountTxLogger.Errorf("发送文件失败，发送错误消息失败: %v", err)
				return nil
			}
			os.Remove(tempFilePath)
			return errors.New("发送文件异常，请检查日志: " + err.Error())
		}

		// 清理临时文件
		os.Remove(tempFilePath)
	} else {
		// 循环结束后，构造并发送完整成功消息
		message := msg.Content + "\n-----------------------------------\n" + "\n复制成功数量：" + strconv.Itoa(len(successAccounts)) + "\n复制成功：" + strings.Join(successAccounts, ",")
		if err := BendiSendText(message, msg.RoomID, msg.Sender); err != nil {
			copyAccountTxLogger.Errorf("发送复制成功消息失败: %v", err)
		}
	}

	err = common.DB.Where("id = ?", jobId).Delete(&job, jobId).Error
	if err != nil {
		copyAccountTxLogger.Errorf("任务完成，删除任务失败: %v", err)
	}
	return nil
}

// 去重函数
func (s *CopyAccountService) removeDuplicates(slice []string) []string {
	seen := make(map[string]bool)
	var result []string
	for _, v := range slice {
		if _, ok := seen[v]; !ok {
			seen[v] = true
			result = append(result, v)
		}
	}
	return result
}

// 去重数据库结构体（只根据 AccountID 去重）
func (s *CopyAccountService) removeDuplicateAccounts(data []models.CopyAccountList) []models.CopyAccountList {
	seen := make(map[int]bool)
	var result []models.CopyAccountList
	for _, v := range data {
		if !seen[v.AccountID] {
			seen[v.AccountID] = true
			result = append(result, v)
		}
	}
	return result
}

// analyzeContent 解析内容为广告主信息数组
func (s *CopyAccountService) analyzeContent(content []string) (*AccountInfoRequest, error) {
	// 初始化结果变量
	var accountIDs []string
	var copyNumber string
	var username string
	var replyFile string
	var subjectName string

	// 编译正则表达式（支持中文逗号、顿号）
	sepRegex, err := regexp.Compile(`[,，、]`)
	if err != nil {
		copyAccountTxLogger.Error("广告主ID分隔符正则表达式编译失败", err)
		return nil, fmt.Errorf("正则表达式编译失败: %w", err)
	}

	// 遍历内容行
	for _, line := range content {
		// 广告主ID
		if strings.HasPrefix(line, "广告主ID:") {
			raw := strings.TrimPrefix(line, "广告主ID:")
			ids := sepRegex.Split(raw, -1)
			for _, id := range ids {
				trimmed := strings.TrimSpace(id)
				if trimmed != "" {
					accountIDs = append(accountIDs, trimmed)
				}
			}
		}
		// 复制数量
		if strings.HasPrefix(line, "复制数量:") {
			copyNumber = strings.TrimSpace(strings.TrimPrefix(line, "复制数量:"))
		}
		// 媒介名字
		if strings.HasPrefix(line, "媒介名字:") {
			username = strings.TrimSpace(strings.TrimPrefix(line, "媒介名字:"))
		}
		// 回复文件
		if strings.HasPrefix(line, "回复文件:") {
			replyFile = strings.TrimSpace(strings.TrimPrefix(line, "回复文件:"))
		}
		// 项目名称
		if strings.HasPrefix(line, "项目名称:") {
			subjectName = strings.TrimSpace(strings.TrimPrefix(line, "项目名称:"))
		}
	}
	// 验证复制数量
	if subjectName == "" {
		return nil, fmt.Errorf("项目名称不能为空")
	}

	// 验证复制数量
	if copyNumber == "" {
		return nil, fmt.Errorf("未找到复制数量")
	}

	num, err := strconv.Atoi(copyNumber)
	if err != nil {
		return nil, fmt.Errorf("复制数量必须为整数: %v", err)
	}
	if num < 1 {
		return nil, fmt.Errorf("复制数量不能小于1")
	}

	if len(accountIDs) < 0 {
		return nil, fmt.Errorf("广告主ID不能为空")
	}

	// 验证回复文件字段（如果存在）
	if replyFile != "" {
		if replyFile != "是" && replyFile != "否" {
			return nil, fmt.Errorf("回复文件字段必须为“是”或“否”")
		}
	}

	// 空数据警告（可选）
	if len(accountIDs) == 0 {
		copyAccountTxLogger.Warn("未解析到有效广告主ID")
		return nil, fmt.Errorf("未解析到有效广告主ID")
	}

	return &AccountInfoRequest{
		AccountID:   accountIDs,
		Number:      copyNumber,
		Username:    username,
		ReplyFile:   replyFile,
		subjectName: subjectName,
	}, nil
}

// 检查复制数量是否超过限制
func (s *CopyAccountService) checkCopyNumber(accounts []string) error {
	if len(accounts) > 10 {
		return fmt.Errorf("复制数量不能大于10个！")
	}
	return nil
}

// uploadMediaToWeCom 获取腾讯文件ID
func (s *CopyAccountService) uploadMediaToWeCom(filePath, fileName string) (string, error) {
	// 构造上传 URL
	uploadUrl := "https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media"
	params := url.Values{}
	params.Set("key", "9a9d5c5d-2c8a-439a-a843-e5c89a30816c")
	params.Set("type", "file")
	uploadUrl += "?" + params.Encode()

	copyAccountTxLogger.Info("上传文件开始", uploadUrl, "文件路径", filePath)

	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return "", fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	// 创建 multipart 缓冲区
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// 手动创建文件部分，精确设置 MIME 类型 (模拟 PHP 的 CURLFile)
	h := make(textproto.MIMEHeader)
	disposition := fmt.Sprintf(`form-data; name="%s"; filename="%s"`, "media", fileName)
	h.Set("Content-Disposition", disposition)

	// 这里设置 Excel 文件的 MIME 类型
	h.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

	part, err := writer.CreatePart(h)
	if err != nil {
		writer.Close()
		return "", fmt.Errorf("创建表单文件部分失败: %v", err)
	}

	// 复制文件内容到表单
	if _, err := io.Copy(part, file); err != nil {
		writer.Close()
		return "", fmt.Errorf("写入表单文件失败: %v", err)
	}

	// 完成 multipart 写入
	if err := writer.Close(); err != nil {
		return "", fmt.Errorf("完成multipart写入失败: %v", err)
	}

	// 创建 HTTP 请求
	req, err := http.NewRequest("POST", uploadUrl, body)
	if err != nil {
		return "", fmt.Errorf("创建请求失败: %v", err)
	}

	// 设置整个请求的 Content-Type (包含 boundary)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	// 发送请求
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
		Timeout: 30 * time.Second,
	}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("上传失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	copyAccountTxLogger.Info("获取后得参数格式：", string(respBody))

	// 解析 JSON 响应
	var result struct {
		ErrCode  int    `json:"errcode"`
		ErrMsg   string `json:"errmsg"`
		MediaID  string `json:"media_id"`
		Type     string `json:"type"`
		CreateAt string `json:"created_at"`
	}
	if err := json.Unmarshal(respBody, &result); err != nil {
		return "", fmt.Errorf("解析响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return "", fmt.Errorf("上传失败[%d]: %s", result.ErrCode, result.ErrMsg)
	}

	if result.MediaID == "" {
		return "", fmt.Errorf("未获取到media_id")
	}
	return result.MediaID, nil
}

func exportToExcel(data []models.TencentData, filePath string) bool {
	file := excelize.NewFile()
	defer file.Close()

	// 创建工作表
	sheet := "Sheet1"
	file.NewSheet(sheet)
	file.SetActiveSheet(0)

	// 写入表头
	headers := []string{"广告主", "ID", "状态", "一级行业", "二级行业", "代理ID", "代理备注", "购买类型", "认证状态"}
	for i, header := range headers {
		cell := fmt.Sprintf("%s1", string('A'+i))
		file.SetCellValue(sheet, cell, header)
	}

	// 写入数据
	for i, item := range data {
		row := i + 2
		file.SetCellValue(sheet, fmt.Sprintf("A%d", row), item.Uname)
		file.SetCellValue(sheet, fmt.Sprintf("B%d", row), item.Uid)
		file.SetCellValue(sheet, fmt.Sprintf("C%d", row), item.CustomerStatusName)
		file.SetCellValue(sheet, fmt.Sprintf("D%d", row), item.IndustryFirstName)
		file.SetCellValue(sheet, fmt.Sprintf("E%d", row), item.IndustrySecondName)
		file.SetCellValue(sheet, fmt.Sprintf("F%d", row), item.AgencyUid)
		file.SetCellValue(sheet, fmt.Sprintf("G%d", row), item.AgencyRemark)
		file.SetCellValue(sheet, fmt.Sprintf("H%d", row), item.BuyingTypeName)
		file.SetCellValue(sheet, fmt.Sprintf("I%d", row), item.IdentityVerifyStatusName)
	}

	// 保存文件
	if err := file.SaveAs(filePath); err != nil {
		copyAccountTxLogger.Errorf("保存Excel失败: %v", err)
		return false
	}
	return true
}

// getAccountCompanyJcRecursion 获取账户公司信息
func (s *CopyAccountService) getAccountCompanyJcRecursion(tencentAdvCookies, tencentAdvGTK string, accountID []string) (map[string]interface{}, error) {
	targetUrl := fmt.Sprintf("https://e.qq.com/agp/advertiser/get_new_list?g_tk=%s", url.QueryEscape(tencentAdvGTK))

	// 构造 POST 数据
	postData := map[string]interface{}{
		"bm_id":              15134508,
		"agency_uid":         6985731,
		"page":               1,
		"page_size":          100,
		"agency_uid_list":    s.getAgencyUidList(), // 需要实现此函数
		"return_fields":      "uname,uid,customer_status_name,industry_first_name,industry_second_name,agency_uid,agency_remark,buying_type_name,identity_verify_status_name",
		"need_operator_data": 0,
		"need_summary_data":  1,
		"uid_list":           accountID,
	}

	// 记录请求数据（在实际应用中替换为您的日志系统）
	copyAccountTxLogger.Printf("提交的参数：%+v", postData)

	// 序列化 JSON 数据
	jsonData, err := json.Marshal(postData)
	if err != nil {
		return nil, fmt.Errorf("JSON序列化失败: %v", err)
	}

	// 创建 HTTP 请求
	req, err := http.NewRequest("POST", targetUrl, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %v", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	req.Header.Set("Cookie", tencentAdvCookies)

	// 创建自定义 Transport 忽略 SSL 验证
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取完整响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	// 记录响应（在实际应用中替换为您的日志系统）
	copyAccountTxLogger.Infof("UpdateAccountStatisticalCount Update yesterday response data: %s", body)

	// 解析 JSON 响应
	var data map[string]interface{}
	if err := json.Unmarshal(body, &data); err != nil {
		return nil, fmt.Errorf("JSON解析失败: %v", err)
	}

	return data, nil
}
